package jfprincesstests.structures.negotiation;

import java.util.Arrays;
import java.util.List;

import laboratoryQ.junit.ignore.patch.BaseTestCase;
import jfprincesstests.fakes.FakeGetIntService;
import jfprincesstests.fakes.IFakeGetIntService;
import jfuzzyprincepless.agents.BaseNegotiationAgent;
import jfuzzyprincepless.agents.INegotiatingAgent;
import jfuzzyprincepless.zarchive.algorithm.structure.ifcnstr.INegotiationCondition;
import jfuzzyprincepless.negotiation.DefaultNegotiationContext;
import jfuzzyprincepless.negotiation.IExecutionContext;
import jfuzzyprincepless.negotiation.INegotiationContext;
import jfuzzyprincepless.negotiation.impl.OverrideInCopyContext;
import jfuzzyprincepless.negotiation.services.IService;
import jfuzzyprincepless.negotiation.services.impl.ServiceRegistry;
import jfuzzyprincepless.zarchive.algorithm.structure.ICommandConstruction;

interface IGetIntService extends INegotiatingAgent, IService {
	public int getInt();
}

class BaseGetIntService
	extends BaseNegotiationAgent
	implements IGetIntService
{
	@Override
	public int getInt() {
		return 123;
	}
}

class SubGetIntService extends BaseGetIntService {
}

class GetIntCmd
	extends BaseNegotiationAgent
	implements ICommandConstruction, IGetIntService
{
	private int val;

	public GetIntCmd(int val) {
		super();
		this.val = val;
	}

	@Override
	public void execute(IExecutionContext context) {
	}

	@Override
	public int getInt() {
		return val;
	}
}

class GetIntAgent
	extends BaseNegotiationAgent
	implements IGetIntService
{
	@Override
	public int getInt() {
		return 456;
	}
}

class GetIntCondition implements INegotiationCondition {
	@Override
	public List<INegotiatingAgent> getAgents() {
		return Arrays.<INegotiatingAgent>asList(
			new GetIntAgent()
		);
	}
}

interface IGetMegaIntService
	extends IGetIntService
{
	public int getMegaint();
}

class GetMegaIntService
	extends BaseNegotiationAgent
	implements IGetMegaIntService
{
	public GetMegaIntService() {
		super();
	}

	@Override
	public int getInt() {
		return 1;
	}

	@Override
	public int getMegaint() {
		return 2;
	}
}

public class TestNegotiationServices extends BaseTestCase {
	public void testGetService() {
		ServiceRegistry serviceRegistry = new ServiceRegistry();
		IGetIntService getIntService =
			serviceRegistry.getService(IGetIntService.class);
		assertNull(getIntService);

		IGetIntService baseGetIntService = new BaseGetIntService();
		serviceRegistry.registerService(baseGetIntService);
		getIntService = serviceRegistry.getService(IGetIntService.class);
		assertNotNull(getIntService);
		assertIsInstance(getIntService, IGetIntService.class);
		assertSame(baseGetIntService, getIntService);

		assertEquals(123, getIntService.getInt());

		serviceRegistry = new ServiceRegistry();
		IGetIntService subGetIntService = new SubGetIntService();
		serviceRegistry.registerService(subGetIntService);
		getIntService = serviceRegistry.getService(IGetIntService.class);
		assertNotNull(getIntService);
		assertIsInstance(getIntService, IGetIntService.class);
		assertSame(subGetIntService, getIntService);
	}

	public void testRegisterMegaint() {
		ServiceRegistry registry = new ServiceRegistry();
		assertNull(registry.getService(IGetMegaIntService.class));
		assertNull(registry.getService(IGetIntService.class));

		registry.registerService(new GetMegaIntService());
		assertEquals(1, registry.getService(IGetMegaIntService.class).getInt());
		assertEquals(2, registry.getService(IGetMegaIntService.class).getMegaint());
		assertEquals(1, registry.getService(IGetIntService.class).getInt());
	}

	/**
	 * DESIGN NOTE:
	 * better to place this method in {@link jfprincesstests.agents.TestAgents}
	 * but here are examples of services
	 */
	public void testBaseAgentRegisterServises() {
		DefaultNegotiationContext context =
			new DefaultNegotiationContext();
		assertNull(context.getService(IGetIntService.class));

		GetIntAgent agent = new GetIntAgent();
		agent.onNegotiationStart(context);
		assertNotNull(context.getService(IGetIntService.class));
		assertEquals(
			456,
			context.getService(IGetIntService.class).getInt()
		);
	}

	public void testDefaultNegotiationContext() {
		DefaultNegotiationContext context =
			new DefaultNegotiationContext();
		INegotiationContext ncontext = context;
		IExecutionContext econtext = context;
		assertSame(ncontext, econtext);

		ncontext.registerService(new BaseGetIntService());
		assertEquals(
			123,
			ncontext.getService(IGetIntService.class).getInt()
		);
	}

	public void testOverrideInCopyContext() {
		INegotiationContext originalContext =
			new DefaultNegotiationContext();
		originalContext.registerService(new GetIntCmd(123));
		OverrideInCopyContext context =
			new OverrideInCopyContext(originalContext);

		IExecutionContext econtext = context;
		assertNotNull(econtext);
		INegotiationContext ncontext = context;
		assertNotNull(ncontext);
		assertEquals(
			123,
			ncontext.getService(IGetIntService.class).getInt()
		);
		assertNull(ncontext.getService(IFakeGetIntService.class));

		ncontext.registerService(new FakeGetIntService(234));
		assertEquals(
			234,
			ncontext.getService(IFakeGetIntService.class).getInt()
		);
		ncontext.registerService(new GetIntCmd(345));
		assertEquals(
			345,
			ncontext.getService(IGetIntService.class).getInt()
		);

		context = new OverrideInCopyContext(originalContext);
		ncontext = context;
		assertNull(ncontext.getService(IFakeGetIntService.class));
		assertEquals(
			123,
			ncontext.getService(IGetIntService.class).getInt()
		);
	}
}
